const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

const resolvePromise = (current, callback, value, resolve, reject) => {
  try {
    const next = callback(value);
    if (current === next) {
      return reject(new TypeError('返回了自己'));
    }
    if (next instanceof MyPromise) next.then(resolve, reject);
    else resolve(next);
  } catch (error) {
    reject(error);
  }
};

class MyPromise {
  constructor(exectuor) {
    try {
      exectuor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  static resolve = (v) => {
    if (v instanceof MyPromise) return v;
    return new MyPromise((r) => r(v));
  };
  static reject = (v) => {
    if (v instanceof MyPromise) return v;
    return new MyPromise((x, r) => r(v));
  };
  static all = (array) =>
    array.reduce(
      (p, item) =>
        p.then((v) => {
          if (item instanceof MyPromise)
            return item.then((next) => v.concat([next]));
          return Promise.resolve(v.concat([item]));
        }),
      Promise.resolve([])
    );

  status = PENDING;
  value = undefined;
  reason = undefined;
  successcb = [];
  failcb = [];

  isPending = () => this.status === PENDING;
  isFulfilled = () => this.status === FULFILLED;
  isRejected = () => this.status === REJECTED;

  resolve = (value) => {
    if (!this.isPending()) return;

    this.status = FULFILLED;
    this.value = value;
    while (this.successcb.length) {
      const fn = this.successcb.shift();
      fn && fn();
    }
  };
  reject = (reason) => {
    if (!this.isPending()) return;

    this.status = REJECTED;
    this.reason = reason;
    while (this.failcb.length) {
      const fn = this.failcb.shift();
      fn && fn();
    }
  };

  then = (successcb, failcb) => {
    const newPromise = new MyPromise((resolve, reject) => {
      const success = () =>
        resolvePromise(
          newPromise,
          successcb || ((v) => v),
          this.value,
          resolve,
          reject
        );
      const fail = () =>
        resolvePromise(
          newPromise,
          failcb || ((v) => MyPromise.reject(v)),
          this.reason,
          resolve,
          reject
        );

      if (this.isFulfilled()) setTimeout(success, 0);
      if (this.isRejected()) setTimeout(fail, 0);
      if (this.isPending()) {
        this.successcb.push(success);
        this.failcb.push(fail);
      }
    });

    return newPromise;
  };
}

module.exports = MyPromise;

// const newPromise = new MyPromise((resolve, reject) => {
//   if (this.isFulfilled()) {
//     setTimeout(() => {
//       try {
//         const next = successcb && successcb(this.value);
//         // 如返回为 Promise 对象, 则移交控制
//         if (newPromise === next) return reject(new TypeError('返回了自己'));
//         if (next instanceof MyPromise) next.then(resolve, reject);
//         else resolve(next);
//       } catch (error) {
//         reject(error);
//       }
//     }, 0);
//   }

//   if (this.isRejected()) {
//     try {
//       setTimeout(() => {
//         const next = failcb && failcb(this.reason);
//         if (newPromise === next) return reject(new TypeError('返回了自己'));
//         if (next instanceof MyPromise) next.then(resolve, reject);
//         else resolve(next);
//       }, 0);
//     } catch (error) {
//       reject(error);
//     }
//   }

//   if (this.isPending()) {
//     // 存储等待状态变更
//     this.successcb.push(() => {
//       setTimeout(() => {
//         try {
//           const next = successcb && successcb(this.value);
//           // 如返回为 Promise 对象, 则移交控制
//           if (newPromise === next)
//             return reject(new TypeError('返回了自己'));
//           if (next instanceof MyPromise) next.then(resolve, reject);
//           else resolve(next);
//         } catch (error) {
//           reject(error);
//         }
//       }, 0);
//     });
//     this.failcb.push(() => {
//       try {
//         setTimeout(() => {
//           const next = failcb && failcb(this.reason);
//           if (newPromise === next)
//             return reject(new TypeError('返回了自己'));
//           if (next instanceof MyPromise) next.then(resolve, reject);
//           else resolve(next);
//         }, 0);
//       } catch (error) {
//         reject(error);
//       }
//     });
//   }
// });
